---
title: 读写HDFS文本数据
---

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

PXF HDFS连接器支持纯分隔和逗号分隔的值表单文本数据。 本节介绍如何使用PXF访问HDFS文本数据，包括如何创建引用了HDFS文件的外部表，查询外部表和向外部表写入数据。

## <a id="prereq"></a>先决条件

在尝试从HDFS读取或向HDFS写入数据之前，请确保已满足PXF Hadoop[先决条件](access_hdfs.html#hadoop_prereq)。

## <a id="profile_text"></a>读取文本数据

当您在读取每行都是单条记录的纯文本分隔或csv数据时，请使用`hdfs:text`配置文件。以下语法创建了一个Greenplum数据库可读外部表，该表引用了HDFS上的此类文本文件：

``` sql
CREATE EXTERNAL TABLE <table_name>
    ( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<path-to-hdfs-file>?PROFILE=hdfs:text')
FORMAT '[TEXT|CSV]' (delimiter[=|<space>][E]'<delim_value>');
```

[CREATE EXTERNAL TABLE](../ref_guide/sql_commands/CREATE_EXTERNAL_TABLE.html)命令中使用的特定关键字和值见下表中描述。

| 关键字  | 值 |
|-------|-------------------------------------|
| \<path&#8209;to&#8209;hdfs&#8209;file\>    | HDFS数据存储中目录或文件的绝对路径 |
| PROFILE    | `PROFILE`关键字必须指定为`hdfs:text` |
| FORMAT | 当\<path-to-hdfs-file\>引用纯文本分隔数据时，请使用`FORMAT` `'TEXT'`。<br> 当\<path-to-hdfs-file\>引用逗号分隔值数据时，请使用`FORMAT` `'CSV'`。|
| delimiter    | 数据中的分隔符。对于`FORMAT` `'CSV'`，默认的\<delim_value\> 是逗号`,`。 当分隔符为转义序列时，在\<delim_value\> 前面加上`E`。示例：`(delimiter=E'\t')`, `(delimiter ':')`。 |

### <a id="profile_text_query"></a>示例：读取HDFS中的文本数据

执行以下步骤以创建示例文本文件、将文件复制到HDFS，并使用PXF `hdfs:text`配置文件创建两个PXF外部表来查询数据：

1. 为PXF示例数据文件创建HDFS目录。例如：

    ``` shell
    $ hdfs dfs -mkdir -p /data/pxf_examples
    ```

2. 创建名为`pxf_hdfs_simple.txt`的纯文本分割数据文件：

    ``` shell
    $ echo 'Prague,Jan,101,4875.33
Rome,Mar,87,1557.39
Bangalore,May,317,8936.99
Beijing,Jul,411,11600.67' > /tmp/pxf_hdfs_simple.txt
    ```

    注意使用逗号`,`来分隔四个数据字段。.

3. 将数据文件添加到HDFS:

    ``` shell
    $ hdfs dfs -put /tmp/pxf_hdfs_simple.txt /data/pxf_examples/
    ```

4. 显示存储在HDFS中的`pxf_hdfs_simple.txt`文件的内容:

    ``` shell
    $ hdfs dfs -cat /data/pxf_examples/pxf_hdfs_simple.txt
    ```

5. 启动`psql`子系统:

    ``` shell
    $ psql -d postgres
    ```

6. 使用PXF `hdfs:text` 配置文件创建一个引用刚刚创建并添加到HDFS的`pxf_hdfs_simple.txt`文件的Greenplum数据库外部表:

    ``` sql
    postgres=# CREATE EXTERNAL TABLE pxf_hdfs_textsimple(location text, month text, num_orders int, total_sales float8)
                LOCATION ('pxf://data/pxf_examples/pxf_hdfs_simple.txt?PROFILE=hdfs:text')
              FORMAT 'TEXT' (delimiter=E',');
    ```

7. 查询外部表:

    ``` sql
    postgres=# SELECT * FROM pxf_hdfs_textsimple;
    ```

    ``` pre
       location    | month | num_orders | total_sales
    ---------------+-------+------------+-------------
     Prague        | Jan   |        101 |     4875.33
     Rome          | Mar   |         87 |     1557.39
     Bangalore     | May   |        317 |     8936.99
     Beijing       | Jul   |        411 |    11600.67
    (4 rows)
    ```

8. 创建第二个引用`pxf_hdfs_simple.txt`的外部表，这一次指定`FORMAT`为`CSV` :

    ``` sql
    postgres=# CREATE EXTERNAL TABLE pxf_hdfs_textsimple_csv(location text, month text, num_orders int, total_sales float8)
                LOCATION ('pxf://data/pxf_examples/pxf_hdfs_simple.txt?PROFILE=hdfs:text')
              FORMAT 'CSV';
    postgres=# SELECT * FROM pxf_hdfs_textsimple_csv;
    ```

    当您为逗号分隔值数据指定`FORMAT 'CSV'`时，不需要提供`delimiter`分隔符选项，因为默认的分隔符是逗号。

## <a id="profile_textmulti"></a>读取含有双引号引起来的换行符的文本数据

使用`hdfs:text:multi`配置文件读取数据中含有引号引起来的换行符，单行或多行的分隔文本数据。以下语法创建一个引用此类文件的Greenplum外部表：

``` sql
CREATE EXTERNAL TABLE <table_name>
    ( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<path-to-hdfs-file>?PROFILE=hdfs:text:multi')
FORMAT '[TEXT|CSV]' (delimiter[=|<space>][E]'<delim_value>');
```

[CREATE EXTERNAL TABLE](../ref_guide/sql_commands/CREATE_EXTERNAL_TABLE.html)命令中使用的特定关键字和值见下表中描述。

| 关键字  | 值 |
|-------|-------------------------------------|
| \<path&#8209;to&#8209;hdfs&#8209;file\>    | HDFS数据存储中目录或文件的绝对路径|
| PROFILE    | `PROFILE`关键字必须指定为`hdfs:text:multi` |
| FORMAT | 当\<path-to-hdfs-file\>引用纯文本分隔数据时，请使用`FORMAT` `'TEXT'`。<br> 当\<path-to-hdfs-file\>引用逗号分隔值数据时，请使用`FORMAT` `'CSV'`。  |
| delimiter    | 数据中的分隔符。对于`FORMAT` `'CSV'`，默认的\<delim_value\> 是逗号`,`。 当分隔符为转义序列时，在\<delim_value\> 前面加上`E`。示例：`(delimiter=E'\t')`, `(delimiter ':')`。 |

### <a id="profile_textmulti_query"></a>示例：在HDFS上读取多行文本数据

执行以下步骤以创建示例文本文件、将文件复制到HDFS, ，并使用PXF `hdfs:text:multi` 配置文件创建一个可读外部表用来查询数据：

1. 创建第二个分隔的纯文本文件：

    ``` shell
    $ vi /tmp/pxf_hdfs_multi.txt
    ```

2. 将以下数据复制/黏贴到`pxf_hdfs_multi.txt`中：

    ``` pre
    "4627 Star Rd.
    San Francisco, CA  94107":Sept:2017
    "113 Moon St.
    San Diego, CA  92093":Jan:2018
    "51 Belt Ct.
    Denver, CO  90123":Dec:2016
    "93114 Radial Rd.
    Chicago, IL  60605":Jul:2017
    "7301 Brookview Ave.
    Columbus, OH  43213":Dec:2018
    ```

    注意使用冒号 `:` 分隔三个字段。 另外请注意第一个（地址）字段周围的引号。这个字段包含了一个嵌入的换行符，用于将街道地址与城市和州分开。

3. 将文本文件复制到HDFS：

    ``` shell
    $ hdfs dfs -put /tmp/pxf_hdfs_multi.txt /data/pxf_examples/
    ```

4. 使用 `hdfs:text:multi` 配置文件创建一个引用HDFS文件 `pxf_hdfs_multi.txt` 的外部表， 确保将`:` (冒号) 标识为字段分隔符：

    ``` sql
    postgres=# CREATE EXTERNAL TABLE pxf_hdfs_textmulti(address text, month text, year int)
                LOCATION ('pxf://data/pxf_examples/pxf_hdfs_multi.txt?PROFILE=hdfs:text:multi')
              FORMAT 'CSV' (delimiter ':');
    ```

    Notice the alternate syntax for specifying the `delimiter`.

5. 查询 `pxf_hdfs_textmulti` 表：

    ``` sql
    postgres=# SELECT * FROM pxf_hdfs_textmulti;
    ```

    ``` pre
             address          | month | year
    --------------------------+-------+------
     4627 Star Rd.            | Sept  | 2017
     San Francisco, CA  94107
     113 Moon St.             | Jan   | 2018
     San Diego, CA  92093
     51 Belt Ct.              | Dec   | 2016
     Denver, CO  90123
     93114 Radial Rd.         | Jul   | 2017
     Chicago, IL  60605
     7301 Brookview Ave.      | Dec   | 2018
     Columbus, OH  43213
    (5 rows)
    ```

## <a id="hdfswrite_text"></a>将文本文件写入HDFS

PXF HDFS连接器 "hdfs:text" 配置文件支持将单行纯文本数据写入HDFS。 当您使用PXF HDFS连接器创建可写外部表时，可以指定在HDFS上的目录名称。 当您向可写外部表写入数据时，您写入的数据块将写入到指定目录中的一个或多个文件。

**注意**: 使用可写配置文件创建的外部表只能用于 `INSERT` 操作。如果要查询写入的数据，则必须另外创建一个引用HDFS目录的可读外部表。

使用以下语法创建一个引用HDFS目录的Greenplum可写外部表： 

``` sql
CREATE WRITABLE EXTERNAL TABLE <table_name>
    ( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<path-to-hdfs-dir>
    ?PROFILE=hdfs:text[&<custom-option>=<value>[...]]')
FORMAT '[TEXT|CSV]' (delimiter[=|<space>][E]'<delim_value>');
[DISTRIBUTED BY (<column_name> [, ... ] ) | DISTRIBUTED RANDOMLY];
```

[CREATE EXTERNAL TABLE](../ref_guide/sql_commands/CREATE_EXTERNAL_TABLE.html)命令中使用的特定关键字和值见下表中描述。

| 关键字  | 值|
|-------|-------------------------------------|
| \<path&#8209;to&#8209;hdfs&#8209;dir\>    | HDFS数据存储中目录的绝对路径 |
| PROFILE    | `PROFILE`关键字必须指定为`hdfs:text` |
| \<custom&#8209;option\>  | \<custom-option\>描述见下方|
| FORMAT | 当\<path-to-hdfs-file\>引用纯文本分隔数据时，请使用`FORMAT` `'TEXT'`。<br> 当\<path-to-hdfs-file\>引用逗号分隔值数据时，请使用`FORMAT` `'CSV'`。 |
| delimiter    | 数据中的分隔符。对于`FORMAT` `'CSV'`，默认的\<delim_value\> 是逗号`,`。 当分隔符为转义序列时，在\<delim_value\> 前面加上`E`。示例：`(delimiter=E'\t')`, `(delimiter ':')`。 |
| DISTRIBUTED BY    | 如果您计划将现有Greenplum数据库表中的数据加载到可写外部表，考虑在可写外部表上使用Greenplum表相同的分布策略或<字段名>。 这样做可以避免数据加载操作中segment节点间额外的数据移动。|

使用 `hdfs:text` 配置文件创建的可写外部表可以选择使用记录或块压缩。 PXF `hdfs:text` 配置文件支持以下压缩编解码器：

- org.apache.hadoop.io.compress.DefaultCodec
- org.apache.hadoop.io.compress.GzipCodec
- org.apache.hadoop.io.compress.BZip2Codec

您可以通过 `CREATE EXTERNAL TABLE` `LOCATION` 子句中自定义选择指定压缩编解码器。 `hdfs:text` 配置文件支持以下自定义写入选项：

| 选项  | 值描述 |
|-------|-------------------------------------|
| COMPRESSION_CODEC    | 压缩编解码器Java类名。 如果未提供此选项，Greenplum数据库不会执行压缩编码。支持的压缩编解码器包括：<br>`org.apache.hadoop.io.compress.DefaultCodec`<br>`org.apache.hadoop.io.compress.BZip2Codec`<br>`org.apache.hadoop.io.compress.GzipCodec` |
| COMPRESSION_TYPE    | 采用的压缩类型; 支持的值为 `RECORD` (默认) 或 `BLOCK` |
| THREAD-SAFE | 确定表查询是否可以在多线程模式下运行的布尔值。 默认为 `TRUE`。 将此选项设置为 `FALSE` 以处理单个线程中所有非线程安全操作 (例如，压缩)的请求。|

### <a id="write_hdfstextsimple_example"></a>示例：将文本数据写入HDFS

此示例使用了[示例：读取HDFS中的文本数据](#profile_text_query)中的数据格式。

| 列名  | 数据类型 |
|-------|-------------------------------------|
| location | text |
| month | text |
| number\_of\_orders | int |
| total\_sales | float8 |

在此示例中您还可以选择在该练习创建的 `pxf_hdfs_textsimple` Greenplum数据库外部表。.

#### <a id="write_hdfstextsimple_proc" class="no-quick-link"></a>步骤

执行以下步骤以使用与上述相同的数据格式创建Greenplum数据库可写外部表，其中一个表将采用压缩。 您将使用PXF `hdfs:text` 配置文件将数据写入HDFS底层目录。您还将创建另外一个可读外部表来读取您写入HDFS目录中的数据。

1. 使用上述数据格式创建Greenplum数据库可写外部表。 写入HDFS目录`/data/pxf_examples/pxfwritable_hdfs_textsimple1`。 使用逗号`,`作为分隔符创建表:

    ``` sql
    postgres=# CREATE WRITABLE EXTERNAL TABLE pxf_hdfs_writabletbl_1(location text, month text, num_orders int, total_sales float8)
                LOCATION ('pxf://data/pxf_examples/pxfwritable_hdfs_textsimple1?PROFILE=hdfs:text')
              FORMAT 'TEXT' (delimiter=',');
    ```
    
    您将`FORMAT` 子句 `delimiter` 的值指定为单个ascii逗号字符`,`。

2. 通过在`pxf_hdfs_writabletbl_1`上调用SQL `INSERT` 命令，将一些单独的记录写入`pxfwritable_hdfs_textsimple1` HDFS目录:

    ``` sql
    postgres=# INSERT INTO pxf_hdfs_writabletbl_1 VALUES ( 'Frankfurt', 'Mar', 777, 3956.98 );
    postgres=# INSERT INTO pxf_hdfs_writabletbl_1 VALUES ( 'Cleveland', 'Oct', 3812, 96645.37 );
    ```

3. (可选) 写入您在[示例：读取HDFS中的文本数据] (#profile_text_query)创建的 `pxf_hdfs_textsimple` 表中的数据到 `pxf_hdfs_writabletbl_1`:

    ``` sql
    postgres=# INSERT INTO pxf_hdfs_writabletbl_1 SELECT * FROM pxf_hdfs_textsimple;
    ```

4. 在另一个终端窗口，显示刚添加到HDFS的数据:

    ``` shell
    $ hdfs dfs -cat /data/pxf_examples/pxfwritable_hdfs_textsimple1/*
    Frankfurt,Mar,777,3956.98
    Cleveland,Oct,3812,96645.37
    Prague,Jan,101,4875.33
    Rome,Mar,87,1557.39
    Bangalore,May,317,8936.99
    Beijing,Jul,411,11600.67
    ```

    因为您在创建可写外部表时使用了逗号 `,` 作为分隔符, 这个字符是HDFS数据中每条记录的字段分隔符.

5. Greenplum数据库不支持直接查询可写外部表。要查询刚刚添加到HDFS的数据， 你必须创建一个引用这个HDFS目录的Greenplum可读外部表：

    ``` sql
    postgres=# CREATE EXTERNAL TABLE pxf_hdfs_textsimple_r1(location text, month text, num_orders int, total_sales float8)
                LOCATION ('pxf://data/pxf_examples/pxfwritable_hdfs_textsimple1?PROFILE=hdfs:text')
			    FORMAT 'CSV';
    ```

    在创建可读外部表时使用 `'CSV'` `FORMAT`，因为您在创建可写外部表时使用逗号 `,` 作为分隔符，即 `'CSV'` `FORMAT` 的默认分隔符。

6. 查询可读外部表:

    ``` sql
    postgres=# SELECT * FROM pxf_hdfs_textsimple_r1 ORDER BY total_sales;
    ```

    ``` pre
     location  | month | num_orders | total_sales 
    -----------+-------+------------+-------------
     Rome      | Mar   |         87 |     1557.39
     Frankfurt | Mar   |        777 |     3956.98
     Prague    | Jan   |        101 |     4875.33
     Bangalore | May   |        317 |     8936.99
     Beijing   | Jul   |        411 |    11600.67
     Cleveland | Oct   |       3812 |    96645.37
    (6 rows)
    ```

    `pxf_hdfs_textsimple_r1` 表包含您单独插入的记录， 以及执行可选步骤时 `pxf_hdfs_textsimple` 表的完整内容。

7. 创建第二个Greenplum数据库可写外部表， 这次使用Gzip压缩并使用冒号 `:` 作为分隔符：

    ``` sql
    postgres=# CREATE WRITABLE EXTERNAL TABLE pxf_hdfs_writabletbl_2 (location text, month text, num_orders int, total_sales float8)
                LOCATION ('pxf://data/pxf_examples/pxfwritable_hdfs_textsimple2?PROFILE=hdfs:text&COMPRESSION_CODEC=org.apache.hadoop.io.compress.GzipCodec')
              FORMAT 'TEXT' (delimiter=':');
    ```

8. 通过直接写入 `pxf_hdfs_writabletbl_2` 表，将一些记录写入`pxfwritable_hdfs_textsimple2` HDFS目录：

    ``` sql
    gpadmin=# INSERT INTO pxf_hdfs_writabletbl_2 VALUES ( 'Frankfurt', 'Mar', 777, 3956.98 );
    gpadmin=# INSERT INTO pxf_hdfs_writabletbl_2 VALUES ( 'Cleveland', 'Oct', 3812, 96645.37 );
    ```

9. 在另一个终端窗口中，显示您刚添加到HDFS的数据；使用 `hdfs dfs` `-text` 选项以文本的形式查看压缩数据：

    ``` shell
    $ hdfs dfs -text /data/pxf_examples/pxfwritable_hdfs_textsimple2/*
    Frankfurt:Mar:777:3956.98
    Cleveland:Oct:3812:96645.3
    ```

    请注意冒号 `:` 是此HDFS数据的字段分隔符。

    要从名为`pxfwritable_hdfs_textsimple2`的新创建的HDFS目录中查询数据，您可以创建一个Greenplum可读外部表并指定 `FORMAT 'CSV' (delimiter=':')`。

